TITLE 11/22/83 BIOS1
.XLIST
INCLUDE DSEG.SRC
INCLUDE POSTEQU.SRC
INCLUDE SYSDATA.INC
INCLUDE SYSDATA.MAC
INCLUDE IAPX286.MAC
.LIST
INCLUDE SEGMENT.SRC

EXTRN	DDS:NEAR
EXTRN	PRT_HEX:NEAR
EXTRN	D1:NEAR
EXTRN	D2:NEAR
EXTRN	P_MSG:NEAR
EXTRN	D2A:NEAR
EXTRN	PRT_SEG:NEAR
EXTRN	PROC_SHUTDOWN:NEAR

PUBLIC	SHUT9
PUBLIC	GATE_A20
PUBLIC CASSETTE_IO_1

;--- INT 15 ----------------------------------------------------:
;    INPUT - CASSETTE I/O FUNCTIONS				:
;	  (AH) = 00						:
;	  (AH) = 01						:
;	  (AH) = 02						:
;	  (AH) = 03						:
;	RETURNS FOR THESE FUNCTIONS ALWAYS (AH) = 86H, CF = 1)	:
;	IF CASSETTE PORT NOT PRESENT				:
;---------------------------------------------------------------:
;    INPUT - UNUSED FUNCTIONS					:
;	  (AH) = 04 THROUGH 7F					:
;	RETURNS FOR THESE FUNCTIONS ALWAYS (AH) = 86H, CF = 1)	:
;---------------------------------------------------------------:
; Extensions							:
;	  (AH) = 80H	DEVICE OPEN				:
;		 (BX) = DEVICE ID				:
;		 (CX) = PROCESS ID				:
;								:
;	  (AH) = 81H	DEVICE CLOSE				:
;		 (BX) = DEVICE ID				:
;		 (CX) = PROCESS ID				:
;								:
;	  (AH) = 82H	PROGRAM TERMINATION			:
;		 (BX) = DEVICE ID				:
;								:
;	  (AH) = 83H	EVENT WAIT				:
;	       (AL) = 0 SET INTERVAL				:
;		(ES:BX) POINTER TO A BYTE IN CALLERS MEMORY	:
;			THAT WILL HAVE THE HIGH ORDER BIT SET	:
;			AS SOON AS POSSIBLE AFTER THE INTERVAL	:
;			EXPIRES.				:
;		(CX,DX) NUMBER OF MICROSECONDS TO ELAPSE BEFORE :
;			POSTING.				:
;	       (AL) = 1 CANCEL					:
;								:
;	  (AH) = 84H	JOYSTICK SUPPORT			:
;	       (DX) = 0 - READ THE CURRENT SWITCH SETTINGS	:
;			RETURNS AL = SWITCH SETTINGS (BITS 7-4) :
;	       (DX) = 1 - READ THE RESISTIVE INPUTS		:
;			RETURNS AX = A(x) VALUE 		:
;				BX = A(y) VALUE 		:
;				CX = B(x) VALUE 		:
;				DX = B(y) VALUE 		:
;								:
;	  (AH) = 85H	SYSTEM REQUEST KEY PRESSED		:
;		(AL) = 00 MAKE OF KEY				:
;		(AL) = 01 BREAK OF KEY				:
;	  (AH) = 86H	WAIT					:
;		(CX,DX) NUMBER OF MICROSECONDS TO ELAPSE BEFORE :
;			RETURN TO CALLER			:
;	  (AH) = 87H	MOVE BLOCK				:
;		(CX)	NUMBER OF WORDS TO MOVE 		:
;		(ES:SI) POINTER TO DESCRIPTOR TABLE		:
;	  (AH) = 88H	EXTENDED MEMORY SIZE DETERMINE		:
;	  (AH) = 89H	PROCESSOR TO VIRTUAL MODE		:
;								:
;	  (AH) = 90H	DEVICE BUSY LOOP			:
;		 (AL)	SEE TYPE CODE				:
;								:
;	  (AH) = 91H	INTERRUPT COMPLETE FLAG SET		:
;		 (AL)	TYPE CODE				:
;			00H -> 7FH				:
;				SERIALLY REUSABLE DEVICES;	:
;				OPERATING SYSTEM MUST SERIALIZE :
;				ACCESS				:
;			80H -> BFH				:
;				REENTRANT DEVICES; ES:BX IS	:
;				USED TO DISTINGUISH DIFFERENT	:
;				CALLS (MULTIPLE I/O CALLS ARE	:
;				ALLOWED SIMULTANEOUSLY) 	:
;			C0H -> FFH				:
;				WAIT ONLY CALLS;  THERE IS NO	:
;				COMPLEMENTARY 'POST' FOR THESE  :
;				WAITS - - THESE ARE TIMEOUT	:
;				ONLY.  TIMES ARE FUNCTION NUMBER:
;				DEPENDENT.			:
;								:
;			TYPE  DESCRIPTION	     TIMEOUT	:
;								:
;			00H = DISK		     YES	:
;			01H = DISKETTE		     YES	:
;			02H = KEYBOARD		     NO 	:
;			80H = NETWORK		     NO 	:
;			     ES:BX --> NCB			:
;			FDH = DISKETTE MOTOR START   YES	:
;			FEH = PRINTER		     YES	:
;---------------------------------------------------------------:
	ASSUME	CS:CODE

CASSETTE_IO_1	PROC	FAR
	STI
	CMP	AH,080H 	; CHECK FOR RANGE
	JB	C1		; RETURN IF 00-7FH
	SUB	AH,080H 	; BASE ON 0
	OR	AH,AH		;
	JZ	DEV_OPEN	; DEVICE OPEN
	DEC	AH		;
	JZ	DEV_CLOSE	; DEVICE CLOSE
	DEC	AH		;
	JZ	PROG_TERM	; PROGRAM TERMINATION
	DEC	AH		;
	JZ	EVENT_WAIT	; EVENT WAIT
	DEC	AH		;
	JZ	JOY_STICK	; JOYSTICK BIOS
	DEC	AH		;
	JZ	SYS_REQ 	; SYSTEM REQUEST KEY
	DEC	AH		;
	JZ	C1_A		; WAIT
	DEC	AH		;
	JNZ	C1_B		;
	JMP	BLOCKMOVE	; MOVE BLOCK

C1_A:	JMP	WAIT		; WAIT

C1_B:	DEC	AH		;

	JNZ	C1_C		;
	JMP	EXT_MEMORY	; GO GET THE EXTENDED MEMORY

C1_C:	DEC	AH
	JNZ	C1_D		; CHECK FOR FUNCTION 89
	JMP	SET_VMODE	; SWAP TO VIRTUAL MODE

C1_D:	SUB	AH,7		; CHECK FOR FUNCTION 90
	JNZ	C1_E		; GO IF NOT
	JMP	DEVICE_BUSY

C1_E:	DEC	AH		; CHECK FOR FUNCTION 8B
	JNZ	C1		; GO IF NOT
	JMP	INT_COMPLETE

C1:	MOV	AH,86H		; SET BAD COMMAND
	STC			; SET CARRY FLAG ON
C1_F:
	RET	2		;


DEV_OPEN:

DEV_CLOSE:

PROG_TERM:

SYS_REQ:
	JMP	C1_F		; RETURN
CASSETTE_IO_1	ENDP

EVENT_WAIT	PROC	NEAR
	ASSUME	CS:CODE,DS:DATA
	PUSH	DS			; SAVE
	CALL	DDS			;
	TEST	RTC_WAIT_FLAG,01	; CHECK FOR FUNCTION ACTIVE
	JZ	EVENT_WAIT_1		;
	POP	DS
	STC				; SET ERROR
	JMP	C1_F			; RETURN
EVENT_WAIT_1:
	CLI				; NO INTERRUPTS ALLOWED
	IN	AL,0A1H 		;ENSURE INTERRUPT UNMASKED
	AND	AL,0FEH 		;
	OUT	0A1H,AL 		;
	MOV	USER_FLAG_SEG,ES	; SET UP TRANSFER TABLE
	MOV	USER_FLAG,BX		;
	MOV	RTC_HIGH,CX		;
	MOV	RTC_LOW,DX		;
	MOV	RTC_WAIT_FLAG,01	; SET ON FUNCTION ACTIVE SWITCH
	MOV	AL,0BH			; ENABLE PIE
	OUT	CMOS_PORT,AL		;
	IN	AL,CMOS_PORT+1		;
	AND	AL,07FH 		;
	OR	AL,040H 		;
	PUSH	AX			;
	MOV	AL,0BH			;
	OUT	CMOS_PORT,AL		;
	POP	AX			;
	OUT	CMOS_PORT+1,AL		;
	STI				; ENABLE INTERRUPTS
	POP	DS
	JMP	C1_F
EVENT_WAIT	ENDP
;--- JOY_STICK -------------------------------------------------:
;	THIS ROUTINE WILL READ THE JOYSTICK PORT		:
;								:
;	INPUT							:
;	(DX)=0 READ THE CURRENT SWITCHES			:
;	       RETURNS (AL)= SWITCH SETTINGS IN BITS 7-4	:
;								:
;	(DX)=1	READ THE RESISTIVE INPUTS			:
;		RETURNS (AX)=A(x) VALUE 			:
;			(BX)=A(y) VALUE 			:
;			(CX)=B(x) VALUE 			:
;			(DX)=B(y) VALUE 			:
;								:
;	CY FLAG ON IF NO ADAPTER CARD OR INVALID CALL		:
;---------------------------------------------------------------:

	ASSUME CS:CODE
JOY_STICK	PROC	NEAR
	STI			; INTERRUPTS BACK ON
	MOV	AX,DX		; GET SUBFUNCTION CODE
	MOV	DX,201H 	; ADDRESS OF PORT
	OR	AL,AL		;
	JZ	JOY_2		; READ SWITCHES
	DEC	AL		;
	JZ	JOY_3		; READ RESISTIVE INPUTS
	JMP	C1		; GO TO ERROR RETURN
JOY_1:
	STI			;
	JMP	C1_F		; GO TO COMMON RETURN
;
JOY_2:
	IN	AL,DX		;
	AND	AL,0F0H 	; STRIP UNWANTED BITS OFF
	JMP	JOY_1		; FINISHED

JOY_3:
	MOV	BL,1		;
	CALL	TEST_CORD	;
	PUSH	CX		; SAVE A(x) VALUE
	MOV	BL,2		;
	CALL	TEST_CORD	;
	PUSH	CX		; SAVE A(y) VALUE
	MOV	BL,4		;
	CALL	TEST_CORD	;
	PUSH	CX		; SAVE B(x) VALUE
	MOV	BL,8		;
	CALL	TEST_CORD	;
	MOV	DX,CX		; SAVE B(y) VALUE
	POP	CX		; GET B(x) VALUE
	POP	BX		; GET A(y) VALUE
	POP	AX		; GET A(x) VALUE
	JMP	JOY_1		; FINISHED - RETURN

TEST_CORD	PROC	NEAR
	PUSH	DX		; SAVE
	CLI			; BLOCK INTERRUPTS WHILE READING
	MOV	AL,0		; SET UP TO LATCH TIMER 0
	OUT	TIMER+3,AL	;
	JMP	SHORT $+2
	IN	AL,TIMER	; READ LOW BYTE OF TIMER 0
	JMP	SHORT $+2
	MOV	AH,AL		;
	IN	AL,TIMER	; READ HIGH BYTE OF TIMER 0
	XCHG	AH,AL		; REARRANGE TO HIGH,LOW
	PUSH	AX		; SAVE
	MOV	CX,4FFH 	; SET COUNT
	OUT	DX,AL		; FIRE TIMER
	JMP	SHORT $+2
TEST_CORD_1:
	IN	AL,DX		; READ VALUES
	TEST	AL,BL		; HAS PULSE ENDED?
	LOOPNZ	TEST_CORD_1	;
	CMP	CX,0		;
	POP	CX		; ORIGINAL COUNT
	JNZ	SHORT TEST_CORD_2	;
	SUB	CX,CX		; SET 0 COUNT FOR RETURN
	JMP	SHORT TEST_CORD_3	; EXIT WITH COUNT = 0
TEST_CORD_2:
	MOV	AL,0		; SET UP TO LATCH TIMER 0
	OUT	TIMER+3,AL	;
	JMP	SHORT $+2
	IN	AL,TIMER	; READ LOW BYTE OF TIMER 0
	MOV	AH,AL		;
	JMP	SHORT $+2
	IN	AL,TIMER	; READ HIGH BYTE OF TIMER 0
	XCHG	AH,AL		; REARRANGE TO HIGH,LOW

	CMP	CX,AX		; CHECK FOR COUNTER WRAP
	JAE	TEST_CORD_4	; GO IF NO
	PUSH	DX		;
	MOV	DX,-1		;

	SUB	DX,AX		; ADJUST FOR WRAP
	ADD	CX,DX		;
	POP	DX		;
	JMP	SHORT TEST_CORD_5

TEST_CORD_4:
	SUB	CX,AX			;
TEST_CORD_5:
	AND	CX,1FF0H		; ADJUST
	SHR	CX,1			;
	SHR	CX,1			;
	SHR	CX,1
	SHR	CX,1

TEST_CORD_3:
	STI				; INTERRUPTS BACK ON
	MOV	DX,201H 		; FLUSH OTHER INPUTS
	PUSH	CX			;
	PUSH	AX
	MOV	CX,4FFH 		; COUNT
TEST_CORD_6:
	IN	AL,DX			;
	TEST	AL,0FH			;
	LOOPNZ	TEST_CORD_6		;

	POP	AX			;
	POP	CX			;
	POP	DX			; SET COUNT

	RET				; RETURN
TEST_CORD	ENDP
JOY_STICK	ENDP

WAIT	PROC	NEAR
	PUSH	DS			; SAVE
	CALL	DDS			;
	TEST	RTC_WAIT_FLAG,01	; TEST FOR FUNCTION ACTIVE
	JZ	WAIT_1
	POP	DS
	STC				; SET ERROR
	JMP	C1_F			; RETURN
WAIT_1:
	CLI				; NO INTERRUPTS ALLOWED
	IN	AL,0A1H 		; ENSURE INTERRUPT UNMASKED
	AND	AL,0FEH 		;
	OUT	0A1H,AL 		;
	MOV	USER_FLAG_SEG,DS	; SET UP TRANSFER TABLE
	MOV	USER_FLAG,OFFSET RTC_WAIT_FLAG
	MOV	RTC_HIGH,CX		;
	MOV	RTC_LOW,DX		;
	MOV	RTC_WAIT_FLAG,01	; SET ON FUNCTION ACTIVE SWITCH
	MOV	AL,0BH			; ENABLE PIE
	OUT	CMOS_PORT,AL		;
	IN	AL,CMOS_PORT+1		;
	AND	AL,07FH 		;
	OR	AL,040H 		;
	PUSH	AX			;
	MOV	AL,0BH			;
	OUT	CMOS_PORT,AL		;
	POP	AX			;
	OUT	CMOS_PORT+1,AL		;
	STI				; ENABLE INTERRUPTS
WAIT_2:
	TEST	RTC_WAIT_FLAG,080H	; CHECK FOR END OF WAIT
	JZ	WAIT_2			;
	MOV	RTC_WAIT_FLAG,0 	; SET FUNCTION INACTIVE
	POP	DS			;
	JMP	C1_F

WAIT	ENDP
PAGE
;------ INT 15 (FUNCTION 87H - MOVE BLOCK) ----------------------
; PURPOSE:							:
;	THIS BIOS FUNCTION PROVIDES A MEANS TO TRANSFER A BLOCK :
;	OF STORAGE TO AND FROM STORAGE ABOVE THE 1 MEG ADDRESS	:
;	RANGE IN VIRTUAL (PROTECTED) MODE.			:
;								:
; ENTRY REQUIREMENTS:						:
;								:
;	ES:SI POINTS TO A DESCRIPTOR TABLE (GDT) BUILT BEFORE	:
;	INTERRUPTING TO THIS FUNCTION.	THESE DESCRIPTORS ARE	:
;	ARE USED BY THIS FUNCTION TO PERFORM THE BLOCK MOVE.	:
;	THE SOURCE AND TARGET DESCRIPTORS BUILT BY THE USER	:
;	MUST HAVE THE SEGMENT LENGTH = 2 * CX - 1 OR GREATER.	:
;	THE DATA ACCESS RIGHTS BYTE WILL BE SET TO CPL0-R/W(93H):
;	THE 24 BIT ADDRESS (BYTE HI, WORD LOW) WILL BE SET	:
;	TO THE TARGET/SOURCE.					:
;								:
; THE DESCRIPTORS ARE DEFINED AS FOLLOWS:			:
;								:
;	1. THE FIRST DESCRIPTOR IS THE REQUIRED DUMMY.		:
;	   (USER INITIALIZED TO 0)				:
;	2. THE SECOND DESCRIPTOR POINTS TO THE GDT TABLE AS	:
;	   A DATA SEGMENT.					:
;	   (USER INITIALIZED TO 0)				:
;	3. THE THIRD  DESCRIPTOR IS THE DESCRIPTOR THAT POINTS	:
;	   TO THE SOURCE TO BE MOVED. (FROM)			:
;	   (USER INITIALIZED)					:
;	4. THE FOURTH DESCRIPTOR IS THE DESCRIPTOR THAT POINTS	:
;	   TO THE DESTINATION. (TO)				:
;	   (USER INITIALIZED)					:
;	5. THE FIFTH IS A DESCRIPTOR THAT THIS FUNCTION USES	:
;	   TO CREATE A VIRTUAL CODE SEGMENT			:
;	   (USER INITIALIZED TO 0)				:
;	6. THE SIXTH IS A DESCRIPTOR THAT THIS FUNCTION USES	:
;	   TO CREATE A VIRTUAL STACK SEGMENT.  (POINTS TO USERS :
;	   STACK)						:
;	   (USER INITIALIZED TO 0)				:
;---------------------------------------------------------------:
PAGE
;------ INT 15 (FUNCTION 87H CONTINUED) ------------------------:
;								:
;	AH=87	(FUNCTION CALL) - BLOCK MOVE.			:
;	ES:SI = LOCATION OF THE GDT TABLE BUILT BY ROUTINE	:
;	USING THIS FUNCTION.					:
;	CX = WORD COUNT OF STORAGE BLOCK TO BE MOVE.		:
;								:
;	     NOTE: MAX COUNT = 8000H  32K WORDS 		:
;								:
; EXIT PARAMETERS:						:
;								:
;	AH = 0	IF SUCCESSFUL					:
;	AH = 1	IF RAM PARITY (PARITY ERROR IS CLEARED) 	:
;	AH = 2	IF EXCEPTION INTERRUPT ERROR			:
;	AH = 3	IF GATE ADDRESS LINE 20 FAILED			:
;	ALL REGISTER ARE RESTORED EXCEPT AX.			:
;	CARRY FLAG = 1 IF ERROR 				:
;	ZERO FLAG  = 1 IF SUCCESSFUL				:
; CONSIDERATIONS:						:
;								:
;	NO INTERRUPTS ARE ALLOWED.				:
;	    TIME OF DAY (ADJUSTED BY USER???)			:
;								:
; DESCRIPTION:							:
;								:
;	1.  CLI (NO INTERRUPT ALLOWED) WHILE THIS FUNCTION IS	:
;	    EXECUTING.						:
;	2.  ADDRESS LINE 20 IS GATED ACTIVE.			:
;	3.  THE IDT (INTERRUPT DESCRIPTOR TABLE) IS ROM RESIDENT:
;	4.  THE CURRENT USER STACK SEGMENT AND OFFSET IS SAVED. :
;	5.  THE GDTR IS LOADED WITH THE OFFSET INTO ES:SI	:
;	6.  THE IDTR SELECTOR IS ROM RESIDENT AND IS LOADED.	:
;	7.  THE PROCESSOR IS PUT IN VIRTUAL MODE		:
;	8.  DATA SEGMENT IS LOADED WITH THE SOURCE DESCRIPTOR	:
;	9.  EXTRA SEGMENT IS LOADED WITH THE TARGET DESCRIPTOR	:
;      10.  DS:SI (SOURCE) ES:DI (TARGET) REP MOVSW IS EXECUTED :
;      11.  SHUTDOWN 09 IS EXECUTED.				:
;      12.  STACK SEGMENT/OFFSET IS RESTORED.			:
;      13.  ADDRESS LINE 20 IS DEGATED. 			:
;      14.  INTERRUPTS ARE ALLOWED				:
;----------------------------------------------------------------
page
;	THE FOLLOWING DIAGRAM DEPICTS THE ORGANIZATION
;	OF GDT.
;---------------------------------------------------------------:
;			     G D T				:
;								:
;			       .-------------.			:
;			       v	     |			:
;     (ES:SI)-->>  +00 .----------------.    |			:
;		       |     DUMMY	|    |			:
;		       |		|    |			:
;		   +08 |----------------|    |			:
;		       |    GDT LOC	| ---'                  :
;		       |		|			:
;		   +10 |----------------|			:
;		       |     SOURCE	|			:
;		       |      GDT	|			:
;		   +18 |----------------|			:
;		       |     TARGET	|			:
;		       |      GDT	|			:
;		   +20 |----------------|			:
;		       |      BIOS	|			:
;		       |       CS	|			:
;		   +28 |----------------|			:
;		       |      SS	|			:
;		       |		|			:
;		       '----------------'                       :
;								:
;								:
;	SAMPLE OF SOURCE OR TARGET DESCRIPTOR			:
;								:
;   SOURCE_TARGET_DEF	     STRUC				:
;								:
;     SEG_LIMIT        DW      ; SEGMENT LIMIT (1-65536 BYTES)	:
;     BASE_LO_WORD     DW      ; 24 BIT SEGMENT PHYSICAL	:
;     BASE_HI_BYTE     DB      ;    ADDRESS (0 TO (16M-1))	:
;     DATA_ACC_RIGHTS  DB      ; ACCESS RIGHTS BYTE		:
;     DATA_RESERVED    DW      ; RESERVED WORD			:
;								:
;   SOURCE_TARGET_DEF	     ENDS				:
;								:
;---------------------------------------------------------------:
;----------------------------------------------------------------------
;     THE GLOBAL DESCRIPTOR TABLE (ACTUAL LOCATION POINTED TO BY ES:SI)
;----------------------------------------------------------------------

BLOCKMOVE_GDT_DEF	STRUC
;
DUMMY	 DQ	0			; FIRST DESCRIPTOR NOT ACCESSIBLE
CGDT_LOC DQ	0			; LOCATION OF CALLING ROUTINE GDT
SOURCE	 DQ	0			; SOURCE DESCRIPTOR
TARGET	 DQ	0			; TARGET DESCRIPTOR
BIOS_CS  DQ	0			; BIOS CODE DESCRIPTOR
TEMP_SS  DQ	0			; STACK DESCRIPTOR
BLOCKMOVE_GDT_DEF	ENDS
;----------------------------------------------------------------------

	ASSUME	CS:CODE
	ASSUME	DS:DATA

BLOCKMOVE   PROC    NEAR

;------- INITIALIZE FOR VIRTUAL MODE

	CLI				; NO INTERRUPTS ALLOWED
	CLD				; SET DIRECTION
	PUSHA				; SAVE GENERAL PURPOSE REGS
	PUSH	ES			; SAVE EXTRA SEGMENT
	PUSH	DS			;

;------- CLEAR EXCEPTION ERROR FLAG

	SUB	AL,AL			;
	OUT	MFG_PORT,AL		; SET TO 0

;------- GATE ADDRESS BIT 20 ON

	MOV	AH,ENABLE_BIT20 	;
	CALL	GATE_A20		;
	CMP	AL,0			; WAS THE COMMAND ACCEPTED?
	JZ	BL4			; GO IF YES
	MOV	AL,03H			; SET THE ERROR FLAG
	OUT	MFG_PORT,AL		;
	JMP	SHUT9			; EARLY EXIT

;------- SET SHUTDOWN RETURN ADDRESS

BL4:	MOV	AL,SHUT_DOWN		; SET THE SHUTDOWN BYTE
	OUT	CMOS_PORT,AL		;  TO SHUT DOWN 9
	JMP	SHORT $+2		; IO DELAY
	MOV	AL,9			;
	OUT	CMOS_PORT+1,AL		;

	;==========================
;-------- SET UP THE GDT DEFINITION
	;==========================
;------- MAKE A 24 BIT ADDRESS OUT OF THE ES:SI

	MOV	AX,ES			; GET THE CURRENT DATA SEGMENT
	MOV	BX,SI			; GET THE CURRENT OFFSET
	MOV	DH,AH			; DEVELOPE THE HIGH BYTE OF THE 24BIT ADDR
	AND	DH,0F0H 		; USE ONLY THE HIGH NIBBLE
	ISHR	DH,4			; SHIFT RIGHT 4
	AND	AH,00FH 		; STRIP HIGH NIBBLE FROM AH
	ISHL	AX,4			; SHIFT AX
	ADD	BX,AX			; DEVELOPE THE LOW WORD ADDRESS
	JNC	BL3A			; GO IF NO CARRY
	INC	DH			; INCREMENT THE HIGH BYTE ADDRESS
	;=================
;-------- SET THE GDT_LOC
	;=================
BL3A:	MOV	ES:[SI].CGDT_LOC.BASE_HI_BYTE,DH  ; SET THE HIGH BYTE
	MOV	ES:[SI].CGDT_LOC.BASE_LO_WORD,BX  ; SET THE LOW WORD

	MOV	ES:[SI].CGDT_LOC.SEG_LIMIT,MAX_SEG_LEN
	MOV	ES:[SI].CGDT_LOC.DATA_RESERVED,0    ; RESERVED
	;==============
;-------- LOAD THE IDT
	;==============
	MOV	BP,OFFSET ROM_IDT_LOC
	SEGOV	CS			; LOAD THE IDT
	LIDT	[BP]			;   REGISTER FROM THIS AREA
	;=============
;------- LOAD THE GDTR
	;=============
	SEGOV	ES			; LOAD GLOBAL DESCRIPTOR TABLE REGISTER
	LGDT	[SI].CGDT_LOC

;------- SET THE DATA SEGMENT TO BIOS RAM

	CALL	DDS			; SET DS TO DATA AREA

;------- SAVE THE CALLING ROUTINE'S STACK

	MOV	AX,SS			; GET THE STACK SEGMENT
	MOV	IO_ROM_SEG,AX		; SAVE STACK SEGMENT
	MOV	AX,SP			; SAVE STACK POINTER
	MOV	IO_ROM_INIT,AX

PAGE
;-------- MAKE A 24 BIT ADDRESS OUT OF THE SS - (SP REMAINS USER SP)

	MOV	AX,SS			; GET THE CURRENT STACK SEGMENT
	MOV	DH,AH			; DEVELOPE THE HIGH BYTE OF THE 24BIT ADDR
	AND	DH,0F0H 		; USE ONLY THE HIGH NIBBLE
	ISHR	DH,4			; SHIFT RIGHT 4
	AND	AH,00FH 		; STRIP HIGH NIBBLE FROM AH
	ISHL	AX,4			; SHIFT AX

;-------- SS IS NOW IN POSITION FOR A 24 BIT ADDRESS --> SETUP THE DESCRIPTOR

BL3:	MOV	ES:[SI].TEMP_SS.BASE_HI_BYTE,DH 	; SET THE HIGH BYTE
	MOV	ES:[SI].TEMP_SS.BASE_LO_WORD,AX 	; SET THE LOW WORD
	MOV	ES:[SI].TEMP_SS.SEG_LIMIT,MAX_SEG_LEN	; SET THE SS SEGMENT LIMIT
	MOV	ES:[SI].TEMP_SS.DATA_ACC_RIGHTS,CPL0_DATA_ACCESS  ; SET CPL 0

;-------- STACK IS NOW SET ---> SET UP THE CODE SEGMENT DESCRIPTOR

	MOV	ES:[SI].BIOS_CS.BASE_HI_BYTE,CSEG@_HI	; HIGH BYTE OF CS=0FH
	MOV	ES:[SI].BIOS_CS.BASE_LO_WORD,CSEG@_LO	; LOW WORD OF CS=0
	MOV	ES:[SI].BIOS_CS.SEG_LIMIT,MAX_SEG_LEN
	MOV	ES:[SI].BIOS_CS.DATA_ACC_RIGHTS,CPL0_CODE_ACCESS
	MOV	ES:[SI].BIOS_CS.DATA_RESERVED,0 	; RESERVED


;-----	SWITCH TO VIRTUAL MODE

	MOV	AX,VIRTUAL_ENABLE	; MACHINE STATUS WORD NEEDED TO
	LMSW	AX			;  SWITCH TO VIRTUAL MODE
	JUMPFAR VIRT,BIOS_CS		; MUST PURGE PRE-FETCH QUEUE
VIRT:

;------- SET STACK SEGMENT  (NEEDED FOR POSSIBLE EXCEPTIONS)

	MOV	AX,TEMP_SS		; USER'S SS+SP IS NOT A DESCRIPTOR
	MOV	SS,AX			;

	MOV	AX,SOURCE		; GET THE SOURCE ENTRY
	MOV	DS,AX			;

	MOV	AX,TARGET		; GET THE TARGET ENTRY
	MOV	ES,AX			;

	SUB	DI,DI			; SET INDEX REGS TO ZERO
	SUB	SI,SI			;

	REP	MOVSW			; MOVE THE BLOCK

;------- CHECK FOR RAM PARITY BEFORE SHUTDOWN

	IN	AL,PORT_B		; GET THE PARITY LATCHES
	AND	AL,PARITY_ERR		; STRIP UNWANTED BITS
	JZ	DONE1			; GO IF NO PARITY ERROR

;-------- CLEAR PARITY BEFORE SHUTDOWN

	MOV	AX,ES:[SI]		; FETCH CURRENT TARGET DATA
	MOV	ES:[SI],AX		; WRITE IT BACK
	MOV	AX,DS:[DI]		; FETCH CURRENT SOURCE DATA
	MOV	DS:[DI],AX		; WRITE IT BACK
	MOV	AL,01			; SET PARITY CHECK ERROR
	OUT	MFG_PORT,AL		;

	IN	AL,PORT_B
	JMP	SHORT $+2		; IO DELAY
	OR	AL,RAM_PAR_OFF		; TOGGLE PARITY CHECK LATCHES
	OUT	PORT_B,AL
	JMP	SHORT $+2		; IO DELAY
	AND	AL,RAM_PAR_ON		;
	OUT	PORT_B,AL


;-------- CAUSE A SHUTDOWN

DONE1:	JMP	PROC_SHUTDOWN		;

	;=====================
;-------- RETURN FROM SHUTDOWN
	;=====================
SHUT9:
;------- ENABLE NMI INTERRUPTS

	SUB	AL,AL			;
	OUT	CMOS_PORT,AL		;

;------- GATE ADDRESS BIT 20 OFF

	MOV	AH,DISABLE_BIT20	;
	CALL	GATE_A20		;
	CMP	AL,0			; COMMAND ACCEPTED?
	JZ	DONE3			; GO IF YES
	IN	AL,MFG_PORT		; CHECK FOR ERROR
	CMP	AL,0			; WAS THERE AN ERROR?
	JNZ	DONE3			; GO IF YES
	MOV	AL,03H			; SET ERROR FLAG
	OUT	MFG_PORT,AL		;

;-------- RESTORE USERS STACK

DONE3:	CALL	DDS			; SET DS TO DATA AREA

	MOV	AX,IO_ROM_SEG		; SAVE STACK SEGMENT
	MOV	SS,AX			; RESTORE THE STACK POINTER

	MOV	AX,IO_ROM_INIT		;
	MOV	SP,AX			;

;-------- RESTORE THE USER DATA SEGMENT

	POP	DS			; RESTORE USER DATA SEGMENT
	POP	ES			; RESTORE USER EXTRA SEGMENT
	POPA				; RESTORE THE GENERAL PURPOSE REGS
	XCHG	AL,AH			; SAVE AL

	IN	AL,MFG_PORT		; CHECK THE ENDING STATUS
	CMP	AL,0			; SET THE ZERO FLAG
	XCHG	AH,AL			; RESTORE AL
	STI				; TURN INTERRUPTS ON
	IRET				; RETURN TO USER

;-------- ROM IDT LOCATION

ROM_IDT_LEN	EQU	32*8		; SIZE OF THE EXCEPTION INTERRUPTS

ROM_IDT_LOC:

	IDT_GDT_DEF	ROM_IDT_LEN,ROM_IDT,CSEG@_HI

;------ THE ROM EXCEPTION INTERRUPT VECTOR GATES

ROM_IDT:
;EXCEPTION 00
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 01
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 02
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 03
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 04
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 05
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 06
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 07
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 08
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 09
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 10
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 11
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 12
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 13
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 14
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 15
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 16
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 17
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 18
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 19
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 20
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 21
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 22
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 23
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 24
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 25
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 26
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 27
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 28
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 29
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 30
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE
;EXCEPTION 31
	DESCR_DEF  GATE,EX_INT,BIOS_CS,0,TRAP_GATE

;------- EXCEPTION INTERRUPT HANDLER

EX_INT:
	MOV	AL,02H			; SET EXCEPTION INT
	OUT	MFG_PORT,AL		;
	JMP	PROC_SHUTDOWN		; CAUSE A EARLY SHUTDOWN
EX_INT1:
	JMP	EX_INT1 		; STAY HERE TILL SHUTDOWN

BLOCKMOVE	ENDP
PAGE
;-------------------------------------------------------------------------------
; GATE_A20
;	THIS ROUTINE CONTROLS A SIGNAL WHICH GATES ADDRESS BIT 20.
;	THE GATE A20 SIGNAL IS AN OUTPUT OF THE 8042 SLAVE PROCESSOR.
;	ADDRESS BIT 20 SHOULD BE GATED ON BEFORE ENTERING PROTECTED MODE.
;	IT SHOULD BE GATED OFF AFTER ENTERING REAL MODE FROM PROTECTED
;	MODE.
; INPUT
;	(AH)=DDH ADDRESS BIT 20 GATE OFF. (A20 ALWAYS ZERO)
;	(AH)=DFH ADDRESS BIT 20 GATE ON. (A20 CONTROLLED BY 80286)
; OUTPUT
;	(AL)=0 OPERATION SUCCESSFUL. 8042 HAS ACCEPTED COMMAND.
;	(AL)=2 FAILURE--8042 UNABLE TO ACCEPT COMMAND.
;-------------------------------------------------------------------------------
GATE_A20	PROC
	CLI			;DISABLE INTERRUPTS WHILE USING 8042
	CALL	EMPTY_8042	;INSURE 8042 INPUT BUFFER EMPTY
	JNZ	GATE_A20_RETURN ;RETURN IF 8042 UNABLE TO ACCEPT COMMAND
	MOV	AL,0D1H 	;8042 COMMAND TO WRITE OUTPUT PORT
	OUT	STATUS_PORT,AL	;OUTPUT COMMAND TO 8042
	CALL	EMPTY_8042	;WAIT FOR 8042 TO ACCEPT COMMAND
	JNZ	GATE_A20_RETURN ;EXIT IF 8042 UNABLE TO ACCEPT COMMAND
	MOV	AL,AH		;8042 PORT DATA
	OUT	PORT_A,AL	;OUTPUT PORT DATA TO 8042
	CALL	EMPTY_8042	;WAIT FOR 8042 TO ACCEPT PORT DATA
;
;----- 8042 OUTPUT WILL SWITCH WITHIN 20 USEC OF ACCEPTING PORT DATA -----
;
GATE_A20_RETURN:
	RET
;-------------------------------------------------------------------------------
; EMPTY_8042
;	THIS ROUTINE WAITS FOR THE 8042 INPUT BUFFER TO EMPTY.
; INPUT
;	NONE
; OUTPUT
;	(AL)=0 8042 INPUT BUFFER EMPTY (ZERO FLAG SET)
;	(AL)=2 TIME OUT, 8042 INPUT BUFFER FULL (NON-ZERO FLAG SET)
;-------------------------------------------------------------------------------
EMPTY_8042:
	PUSH	CX		;SAVE CX
	SUB	CX,CX		;CX=0, WILL BE USED AS TIME OUT VALUE
EMPTY_LOOP:
	IN	AL,STATUS_PORT	;READ 8042 STATUS PORT
	AND	AL,INPT_BUF_FULL;TEST INPUT BUFFER FULL FLAG (BIT 1)
	LOOPNZ	EMPTY_LOOP	;LOOP UNTIL INPUT BUFFER EMPTY OR TIME OUT
	POP	CX		;RESTORE CX
	RET

GATE_A20	ENDP
PAGE
;------ INT 15 (FUNCTION 88H - IO MEMORY SIZE DETERMINE) --------
; EXT_MEMORY							:
;	THIS ROUTINE RETURNS  THE AMOUNT OF MEMORY IN THE	:
;	SYSTEM THAT IS LOCATED STARTING AT THE 1024K ADDRESSING :
;	RANGE, AS DETERMINED BY THE POST ROUTINES.		:
;	NOTE THAT THE SYSTEM MAY NOT BE ABLE TO USE I/O MEMORY	:
;	UNLESS THERE IS A FULL COMPLEMENT OF 512K OR 640 BYTES	:
;	ON THE PLANAR.	THIS SIZE IS STORED IN CMOS AT ADDRESS	:
;	30 AND 31.						:
; INPUT 							:
;	AH = 88H						:
;								:
;	THE IO MEMORY SIZE VARIABLE IS SET DURING POWER ON	:
;	DIAGNOSTICS ACCORDING TO THE FOLLOWING ASSUMPTIONS:	:
;								:
;	1. ALL INSTALLED MEMORY IS FUNCTIONAL.			:
;								:
;	2. ALL MEMORY FROM 0 TO 640K MUST BE CONTIGUOUS.	:
;								:
; OUTPUT							:
;	(AX) = NUMBER OF CONTIGUOUS 1K BLOCKS OF MEMORY A	:
;	       AVAILABLE STARTING AT ADDRESS 1024K.		:
;								:
;----------------------------------------------------------------
EXT_MEMORY	PROC
	STI				; INTERRUPTS BACK ON
	MOV	AL,31H			; GET THE HIGH BYTE OF IO MEMORY
	OUT	CMOS_PORT,AL		;
	JMP	SHORT $+2		; IO DELAY
	IN	AL,CMOS_PORT+1		;
	XCHG	AL,AH			; PUT HIGH BYTE IN POSITION (AH)
	MOV	AL,30H			; GET THE LOW BYTE OF IO MEMORY
	OUT	CMOS_PORT,AL		;
	JMP	SHORT $+2		; IO DELAY
	IN	AL,CMOS_PORT+1		;
	IRET				; RETURN TO USER
EXT_MEMORY	ENDP
PAGE
;------ INT 15H (FUNCTION 89H) ----------------------------------
; PURPOSE:							:
;	THIS BIOS FUNCTION PROVIDES A MEANS TO THE USER TO	:
;	SWITCH INTO VIRTUAL (PROTECTED) MODE.  UPON COMPLETION	:
;	OF THIS FUNCTION THE PROCESSOR WILL BE IN  VIRTUAL	:
;	(PROTECTED) MODE AND CONTROL WILL BE TRANSFERED TO THE	:
;	CODE SEGMENT THAT WAS SPECIFIED BY THE USER.		:
;								:
; ENTRY REQUIREMENTS:						:
;								:
;	ES:SI POINTS TO A DESCRIPTOR TABLE (GDT) BUILT BEFORE	:
;	INTERRUPTING TO THIS FUNCTION.	THESE DESCRIPTORS ARE	:
;	ARE USED BY THIS FUNCTION TO INITIALIZE THE IDTR, THE	:
;	GDTR AND THE STACK SEGMENT SELECTOR.  THE DATA SEGMENT	:
;	(DS) SELECTOR AND THE EXTRA SEGMENT (ES) SELECTOR WILL	:
;	BE INITIALIZE TO DESCRIPTORS BUILT BY THE ROUTINE USING :
;	THIS FUNCTION.						:
;	BH - OFFSET INTO THE INTERRUPT DESCRIPTOR TABLE 	:
;	     STATING WHERE THE FIRST EIGHT HARDWARE INTERRUPTS	:
;	     WILL BEGIN. ( INTERRUPT LEVEL 1 )			:
;	BL - OFFSET INTO THE INTERRUPT DESCRIPTOR TABLE 	:
;	     STATING WHERE THE SECOND EIGHT HARDWARE		:
;	     INTERRUPTS WILL BEGIN. ( INTERRUPT LEVEL 2 )	:
;								:
; THE DESCRIPTORS ARE DEFINED AS FOLLOWS:			:
;								:
;	1.  THE FIRST DESCRIPTOR IS THE REQUIRED DUMMY. 	:
;	    (USER INITIALIZED TO 0)				:
;	2.  THE SECOND DESCRIPTOR POINTS TO THE GDT TABLE AS	:
;	    A DATA SEGMENT.					:
;	    (USER INITIALIZED)					:
;	3.  THE THIRD DESCRIPTOR POINTS TO THE USER DEFINED	:
;	    INTERRUPT DESCRIPTOR TABLE (IDT).			:
;	    (USER INITIALIZED)					:
;	4.  THE FORTH DESCRIPTOR POINTS TO THE USER'S DATA      :
;	    SEGMENT (DS).					:
;	    (USER INITIALIZED)					:
;	5.  THE FIFTH DESCRIPTOR POINTS TO THE USER'S EXTRA     :
;	    SEGMENT (ES).					:
;	    (USER INITIALIZED)					:
;	6.  THE SIXTH DESCRIPTOR POINTS TO THE USER'S STACK     :
;	    SEGMENT (SS).					:
;	    (USER INITIALIZED)					:
;	7.  THE SEVENTH DESCRIPTOR POINTS TO THE CODE SEGMENT	:
;	    THAT THIS FUNCTION WILL RETURN TO.			:
;	    (USER INITIALIZED TO THE USER'S CODE SEGMENT.)      :
;	8.  THE EIGTH DESCRIPTOR IS USED BY THIS FUNCTION TO	:
;	    ESTABLISH A CODE SEGMENT FOR ITSELF. THIS IS	:
;	    NEEDED SO THAT THIS FUNCTION CAN COMPLETE IT'S      :
;	    EXECUTION WHILE IN PROTECTED MODE. WHEN CONTROL	:
;	    GETS PASSED TO THE USER'S CODE THIS DESCRIPTOR CAN  :
;	    BE USED BY HIM IN ANY WAY HE CHOOSES.		:
;								:
;    NOTE -  EACH DESCRIPTOR MUST CONTAIN ALL THE NECESSARY	:
;	     DATA  I.E. THE LIMIT,  BASE ADDRESS AND THE ACCESS :
;	     RIGHTS BYTE.					:
;								:
;	AH=89H	(FUNCTION CALL) 				:
;	ES:SI = LOCATION OF THE GDT TABLE BUILD BY ROUTINE	:
;	USING THIS FUNCTION.					:
;								:
; EXIT PARAMETERS:						:
;								:
;	AH = 0	IF SUCCESSFUL					:
;	ALL SEGMENT REGISTERS ARE CHANGED, AX AND BP DESTROYED	:
;								:
; CONSIDERATIONS:						:
;								:
;	1.  NO BIOS AVAILABLE TO USER. USER MUST HANDLE ALL	:
;	    I/O COMMANDS.					:
;	2.  INTERRUPTS - INTERRUPT VECTOR LOCATIONS MUST BE	:
;	    MOVED,  DUE TO THE 286 RESERVED AREAS.  THE 	:
;	    HARDWARE INTERRUPT CONTROLLERS MUST BE REINITIALIZED:
;	    TO DEFINE LOCATIONS THAT DO NOT RESIDE IN THE 286	:
;	    RESERVED AREAS.					:
;EXCEPTION INTERRUPT TABLE AND HANDLER MUST BE	     :
;	    INITIALIZED BY THE USER.				:
;	4.  THE INTERRUPT DESCRIPTOR TABLE MUST NOT OVERLAP	:
;	    THE REAL MODE BIOS INTERRUPT DESCRIPTOR TABLE.	:
;	5.  THE FOLLOWING GIVES AN IDEA OF WHAT THE USER CODE	:
;	    SHOULD LOOK LIKE WHEN INVOKING THIS FUNCTION.	:
;								:
;	Real mode --->	  "USER CODE"                           :
;		   "      MOV   AX,GDT SEGMENT                  :
;		   "      MOV   ES,AX                           :
;		   "      MOV   SI,GDT OFFSET                   :
;		   "      MOV   BH,HARDWARE INT LEVEL 1 OFFSET  :
;		   "      MOV   BL,HARDWARE INT LEVEL 2 OFFSET  :
;		   "      MOV   AH,89H                          :
;		   "      INT   15H                             :
;    Virtual mode --->	  "USER CODE"                           :
;								:
; DESCRIPTION:							:
;								:
;	1.  CLI (NO INTERRUPTS ALLOWED) WHILE THIS FUNCTION IS	:
;	    EXECUTING.						:
;	2.  ADDRESS LINE 20 IS GATED ACTIVE.			:
;	3.  THE CURRENT USER STACK SEGMENT DESCRIPTOR IS	:
;	    INITIALIZED.					:
;	4.  THE GDTR IS LOADED WITH THE GDT BASE ADDRESS.	:
;	5.  THE IDTR IS LOADED WITH THE IDT BASE ADDRESS.	:
;	6.  THE 8259 IS REINITIALIZED WITH THE NEW INTERRUPT	:
;	    OFFSETS.						:
;	7.  THE PROCESSOR IS PUT IN VIRTUAL MODE WITH THE CODE	:
;	    SEGMENT DESIGNATED FOR THIS FUNCTION.		:
;	8.  DATA SEGMENT IS LOADED WITH THE USER DEFINED	:
;	    SELECTOR FOR THE DS REGISTER.			:
;	9.  EXTRA SEGMENT IS LOADED WITH THE USER DEFINED	:
;	    SELECTOR FOR THE ES REGISTER.			:
;	10. STACK SEGMENT IS LOADED WITH THE USER DEFINED	:
;	    SELECTOR FOR THE SS REGISTER.			:
;	11. CODE SEGMENT DESCRIPTOR SELECTOR VALUE IS		:
;	    SUBSTITUTED ON THE STACK FOR RETURN TO USER.	:
;	12. WE TRANSFER CONTROL TO THE USER WITH INTERRUPTS	:
;	    DISABLED.						:
;----------------------------------------------------------------
page
;	THE FOLLOWING DIAGRAM DEPICTS THE ORGANIZATION
;	OF GDT.
;-------------------------------------------------------------------------------
;			     G D T					       :
;									       :
;			       .-------------.				       :
;			       v	     |				       :
;     (ES:SI)-->>  +00 .----------------.    |				       :
;		       |     DUMMY	|    |				       :
;		       |		|    |				       :
;		   +08 |----------------|    |				       :
;		       |      GDT	| ---'                                 :
;		       |		|				       :
;		   +10 |----------------|				       :
;		       |      IDT	|				       :
;		       |		|				       :
;		   +18 |----------------|				       :
;		       |      DS	|				       :
;		       |		|				       :
;		   +20 |----------------|				       :
;		       |      ES	|				       :
;		       |		|				       :
;		   +28 |----------------|				       :
;		       |      SS	|				       :
;		       |		|				       :
;		   +30 |----------------|				       :
;		       |      CS	|				       :
;		       |		|				       :
;		   +38 |----------------|				       :
;		       |   TEMP BIOS	|				       :
;		       |      CS	|				       :
;		       |----------------|				       :
;									       :
;-------------------------------------------------------------------------------

;----------------------------------------------------------------------
;     THE GLOBAL DESCRIPTOR TABLE (ACTUAL LOCATION POINTED TO BY ES:SI)
;----------------------------------------------------------------------

VIRTUAL_ENABLE_GDT_DEF	STRUC
	DQ	?		; FIRST DESCRIPTOR NOT ACCESSIBLE
GDTPTR	DQ	?		; GDT DESCRIPTOR
IDTPTR	DQ	?		; IDT DESCRIPTOR
USER_DS DQ	?		; USER DATA SEGMENT DESCRIPTOR
USER_ES DQ	?		; USER EXTRA SEGMENT DESCRIPTOR
USER_SS DQ	?		; USER STACK SEGMENT DESCRIPTOR
USER_CS DQ	?		; USER CODE SEGMENT DESCRIPTOR
BIO_CS	DQ	?		; TEMPORARY BIOS DESCRIPTOR
VIRTUAL_ENABLE_GDT_DEF	ENDS

	ASSUME	CS:CODE
	ASSUME	DS:DATA

X_VIRTUAL	PROC	FAR
SET_VMODE:

	CLI				; NO INTERRUPTS ALLOWED

;------- ENABLE ADDRESS LATCH BIT 20

	MOV	AH,ENABLE_BIT20 	; ENABLE BIT 20 FOR ADDRESS GATE
	CALL	GATE_A20		;
	CMP	AL,0			; WAS THE COMMAND ACCEPTED?
	JZ	BIT20_ON		; GO IF YES
	MOV	AH,0FFH 		; SET THE ERROR FLAG
	STC				; SET CARRY
	IRET				; EARLY EXIT


BIT20_ON:
	SEGOV	ES			; LOAD THE GLOBAL DESCRIPTOR TABLE REG
	LGDT	[SI].GDTPTR
	SEGOV	ES			; LOAD THE INTERRUPT DESCRIPTOR TABLE REG
	LIDT	[SI].IDTPTR

;-----------------------------------------------------------------------------
; REINITIALIZE THE 8259 INTERRUPT CONTROLLER #1 TO THE USER SPECIFIED OFFSET  :
;-----------------------------------------------------------------------------

	MOV	AL,11H			; START INITIALIZATION SEQUENCE-ICW1
	OUT	INTA00,AL		; EDGE,INTERVAL-8,MASTER,ICW4 NEEDED
	JMP	SHORT $+2		;
	MOV	AL,BH			; HARDWARE INT'S START AT INT # (BH)
	OUT	INTA01,AL		; SEND ICW2
	JMP	SHORT $+2		;
	MOV	AL,04H			; SEND ICW3 - MASTER LEVEL 2
	OUT	INTA01,AL		;
	JMP	SHORT $+2		;
	MOV	AL,01H			; SEND ICW4 - MASTER,8086 MODE
	OUT	INTA01,AL		;
	JMP	SHORT $+2		;
	MOV	AL,0FFH 		; MASK OFF ALL INTERRUPTS
	OUT	INTA01,AL

;-----------------------------------------------------------------------------
; REINITIALIZE THE 8259 INTERRUPT CONTROLLER #2 TO THE USER SPECIFIED OFFSET  :
;-----------------------------------------------------------------------------

	MOV	AL,11H			; INITIALIZE SEQUENCE-ICW1 FOR SLAVE
	OUT	INTB00,AL		; EDGE,INTERVAL-8,MASTER,ICW4 NEEDED
	JMP	SHORT $+2		;
	MOV	AL,BL			; HARDWARE INT'S START AT INT # (BL)
	OUT	INTB01,AL		; SEND ICW2
	MOV	AL,02H			;
	JMP	SHORT $+2		;
	OUT	INTB01,AL		; SEND ICW3 - SLAVE LEVEL 2
	JMP	SHORT $+2		;
	MOV	AL,01H			;
	OUT	INTB01,AL		; SEND ICW4 - SLAVE,8086 MODE
	JMP	SHORT $+2		;
	MOV	AL,0FFH 		;
	OUT	INTB01,AL		; MASK OFF ALL INTERRUPTS

;-----------------------------------------------------------------------------
; SETUP BIOS CODE SEGMENT DESCRIPTOR					      :
;-----------------------------------------------------------------------------

	MOV	ES:[SI].BIO_CS.SEG_LIMIT,MAX_SEG_LEN	; SET LENGTH
	MOV	ES:[SI].BIO_CS.BASE_HI_BYTE,CSEG@_HI	; SET HIGH BYTE OF CS=0F
	MOV	ES:[SI].BIO_CS.BASE_LO_WORD,CSEG@_LO	; SET LOW WORD OF CS=0
							; SET ACCESS RIGHTS BYTE
	MOV	ES:[SI].BIO_CS.DATA_ACC_RIGHTS,CPL0_CODE_ACCESS
	MOV	ES:[SI].BIO_CS.DATA_RESERVED,0		; ZERO RESERVED AREA

;-----------------------------------------------------------------------------
; ENABLE PROTECTED MODE 						      :
;-----------------------------------------------------------------------------


	MOV	AX,VIRTUAL_ENABLE	; MACHINE STATUS WORD NEEDED TO
	LMSW	AX			;  SWITCH TO VIRTUAL MODE
	JUMPFAR VMODE,BIO_CS	       ; MUST PURGE PRE-FETCH QUEUE

VMODE:
;-----------------------------------------------------------------------------
; SETUP USER SEGMENT REGISTERS						      :
;-----------------------------------------------------------------------------

	MOV	AX,USER_DS		; SETUP USER'S DATA SEGMENT
	MOV	DS,AX			;
	MOV	AX,USER_ES		; SETUP USER'S EXTRA SEGMENT
	MOV	ES,AX			;
	MOV	AX,USER_SS		; SETUP USER'S STACK SEGMENT
	MOV	SS,AX			;

;-----------------------------------------------------------------------------
; PUT TRANSFER ADDRESS ON THE STACK AND RETURN TO THE USER		      :
;-----------------------------------------------------------------------------

	POP	BX			; GET RETURN IP FROM THE STACK
	ADD	SP,4			; NORMALIZE STACK POINTER
	IPUSH	USER_CS 		; SET STACK FOR A RETURN FAR
	PUSH	BX
	RET				; RETURN TO USER IN VIRTUAL MODE

X_VIRTUAL	ENDP

;--- DEVICE BUSY AND INTERRUPT COMPLETE ------------------------:
;								:
;	THIS ROUTINE IS A TEMPORY HANDLER FOR DEVICE BUSY	:
;	AND INTERRUPT COMPLETE					:
;								:
;	INPUT							:
;	SEE PROLOG						:
;								:
;---------------------------------------------------------------:
DEVICE_BUSY	PROC	NEAR
	CLC				; TURN CARRY OFF
	JMP	C1_F			; RETURN WITH CARRY FLAG
DEVICE_BUSY	ENDP

INT_COMPLETE	PROC	NEAR
	IRET				; RETURN
INT_COMPLETE	ENDP


CODE	ENDS
	END
